/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Openfire-C.

Openfire-C is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Openfire-C is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Openfire-C.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "packet_creation/XfirePacketsClientIM.h"

int XfireAnalyze_hIM(XFINST inst, struct XfirePacket *packet) {
	/* Instant message, receiving acknowledgement, P2P info, typing status
	 * http://xfireplus.com/xfwiki/index.php/Packet_85_00-00_00
	 * http://xfireplus.com/xfwiki/index.php/Packet_85_00-01_00
	 * http://xfireplus.com/xfwiki/index.php/Packet_85_00-02_00
	 * http://xfireplus.com/xfwiki/index.php/Packet_85_00-03_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	struct XfirePacket *peermsg = XfirePacketGetPacketAttribute(packet, (unsigned const char *)"peermsg");
	non0string *sid_value = XfirePacketGetStringAttribute(packet, (unsigned const char *)"sid");
	
	if (peermsg && sid_value) {
		struct XfFriend *xff = XfireInst_FindUserBySid(inst, sid_value);
		
		unsigned int *msgtype = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"msgtype");
		if (msgtype) {
			/* Hack the packet id to contain msgtype for external handler calling */
			packet->pid |= (*msgtype) << 16;
			
			switch (*msgtype) {
				case XFPIDP_IM_IM:
				{
					unsigned int *imindex = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"imindex");
					non0string *message = XfirePacketGetStringAttribute(peermsg, (unsigned const char *)"im");
					
					/* define external handler function type and calling parameters */
					#define _XFABT struct XfFriend*, non0string*, unsigned int
					#define _XFABP xff, message, *imindex
					
					if (imindex && message) {
						/* include external handlers calling */
						#include "XfirePacketAnalyzeExt.inc"
						
						/* internal handling */
						if (retval & XFIH_HANDLED) {
							XfireInst_SendPacket(inst, XfirePHc_IMack(n0scopy(sid_value), *imindex) );
						}
					}
					else {
						retval = XFIH_UNKNOWN;
					}					
					break;
				}
				case XFPIDP_IM_ACK:
				{
					unsigned int *imindex = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"imindex");
					
					/* define external handler function type and calling parameters */
					#define _XFABT struct XfFriend*, unsigned int
					#define _XFABP xff, *imindex
					if (imindex) {
						/* include external handlers calling */
						#include "XfirePacketAnalyzeExt.inc"
						
						/* No internal handling required */
					}
					else {
						retval = XFIH_UNKNOWN;
					}					
					break;
				}
				case XFPIDP_IM_TYPING:
				{
					unsigned int *istyping = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"typing");
					
					/* define external handler function type and calling parameters */
					#define _XFABT struct XfFriend*, unsigned int
					#define _XFABP xff, *istyping
					if (istyping) {
						/* include external handlers calling */
						#include "XfirePacketAnalyzeExt.inc"
						
						/* No internal handling required */
					}
					else {
						retval = XFIH_UNKNOWN;
					}					
					break;
				}
				case XFPIDP_IM_P2P:
				{
					unsigned int *ip = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"ip");
					unsigned int *port = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"port");
					unsigned int *localip = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"localip");
					unsigned int *localport = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"localport");
					unsigned int *nattype = XfirePacketGetIntegerAttribute(peermsg, (unsigned const char *)"status");
					non0string   *salt = XfirePacketGetStringAttribute(peermsg, (unsigned const char *)"salt");
					
					/* define external handler function type and calling parameters */
					#define _XFABT struct XfFriend*, struct XfFriendP2P*
					#define _XFABP xff, p2p
					
					if (ip && port && localip && localport && nattype && salt) {
						struct XfFriendP2P *p2p = XfireFriendP2Pinfo();
						p2p->ip = *ip;
						p2p->port = *port;
						p2p->localip = *localip;
						p2p->localport = *localport;
						p2p->status = *nattype;
						p2p->salt = n0scopy(salt);
						
						/* include external handlers calling */
						#include "XfirePacketAnalyzeExt.inc"
						
						/* Internal handling */
						if (retval & XFIH_HANDLED) {
							if (xff) {
								FreeXfireFriendP2Pinfo(xff->extdata->p2p);
								xff->extdata->p2p = p2p;
							}
							else {
								/* For some reason the user was not found,
								 * mark possible error in library */
								retval |= XFIH_NONFATAL;
							}
						}
						else {
							/* Free the p2p data */
							FreeXfireFriendP2Pinfo(p2p);
						}
					}
					else {
						retval = XFIH_UNKNOWN;
					}					
					break;
				}
				default:
				{
					#define _XFABT struct XfirePacket*
					#define _XFABP peermsg
					/* include external handlers calling */
					#include "XfirePacketAnalyzeExt.inc"
					break;
				}
			}
		}
		else {
			/* Not all attributes found */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clear up, all data was part of the original packet */
	
	return retval;
}

int XfireAnalyze_hBroadcast(XFINST inst, struct XfirePacket *packet) {
	/* A message from Xfire offices!
	 * http://xfireplus.com/xfwiki/index.php/Packet_a9_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT non0string*, unsigned int
	#define _XFABP message, *attr34
	
	non0string   *message = XfirePacketGetStringAttribute (packet, SHORT_ATTRIBUTE(\x2e));
	unsigned int *attr34  = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x34));
	
	if (message && attr34) {
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* no internal handling required */
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clear up */
	
	return retval;
}
